package com.ruoyi.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.bizsys.domain.CustomerInfo;
import com.ruoyi.bizsys.domain.ExtTransferResult;
import com.ruoyi.bizsys.domain.LoanIou;
import com.ruoyi.bizsys.domain.RepaymentOrder;
import com.ruoyi.bizsys.service.*;
import com.ruoyi.bizsys.utils.BizConstants;
import com.ruoyi.business.domain.TransferVo;
import com.ruoyi.business.service.*;
import com.ruoyi.common.constant.LoanConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.FeishuUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.extdata.service.IExternalApiService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Date;

@Slf4j
@Service
public class PaystackRepaymentServiceImpl extends BaseService implements IPaystackRepaymentService {

    @Autowired
    IExternalApiService externalApiService;

    @Autowired
    IRepaymentOrderService repaymentOrderService;

    @Autowired
    IBRepaymentService ibRepaymentService;

    @Autowired
    ILoanIouService loanIouService;

    @Autowired
    RedisCache redisCache;

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    IRepaymentExceptionService iRepaymentExceptionService;

    @Autowired
    @Lazy
    IRepaymentSmsService iRepaymentSmsService;
    @Autowired
    IDoRepaymentLastService doRepaymentLastService;
    @Autowired
    IRepayToWalletService repayToWalletService;

    @Autowired
    IExtTransferResultService transferResultService;

    @Autowired
    IBLoanInfoService bLoanInfoService;

    @Autowired
    IRepaymentService iRepaymentService;
    @Autowired
    ILoanOverflowService iLoanOverflowService;
//
//    @Override
//    public void repaymentWebHook(String serialNo, JSONObject jsonObject){
//
//        String eventType = "charge.success";
//        CustomerInfo custInfo = new CustomerInfo();
//        RepaymentOrder order = new RepaymentOrder();
//        order.setPayTransSerialNo(serialNo);
//        order.setState(BizConstants.BIZ_STATUS_1);
//        order.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_DOING);
//        List<RepaymentOrder> repaymentOrderList = repaymentOrderService.selectRepaymentOrderList(order);
//
//        //锁住客户账户再操作
//        if (CollectionUtils.isEmpty(repaymentOrderList)) {
//            externalApiService.dealTransferData(eventType, "webhook", custInfo, jsonObject);
//            log.info("未找到对应的repaymentOrder，serialNo：{}",serialNo);
//            return;
//        }
//        RepaymentOrder repaymentOrder = repaymentOrderList.get(0);
//
//        String lockKey = LoanConstants.CUST_ACCOUNT_LOCK_KEY_PREFIX + repaymentOrder.getCustNo();
//
//        int j = 0;//重试次数
//        while (j < LoanConstants.CUST_ACCOUNT_LOCK_REGET_COUNT) {//重试次数内
//            j++;
//            log.info("deferredWithholding客户号{}第{}次获取账户锁", repaymentOrder.getCustNo(), j);
//            String lockValue = IdUtils.simpleUUID();
//            boolean lock = redisCache.lock(lockKey,lockValue);//获取锁
//
//            if (lock) {
//                try {
//                    long start = System.currentTimeMillis();
//                    //再次查找repaymentOrder
//                    repaymentOrder = repaymentOrderService.selectRepaymentOrderById(repaymentOrder.getId());
//                    if(repaymentOrder.getRepayStatus()!=BizConstants.REPAYMENT_ORDER_STATUS_DOING){
//                        break;
//                    }
//
//                    custInfo.setCustNo(repaymentOrder.getCustNo());
//                    custInfo.setUserId(getCustInfo(repaymentOrder.getCustNo()).getUserId());
//
//                    repaymentOrder.setPayTime(new Date());
//                    repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);
//
//                    externalApiService.dealTransferData(eventType, "webhook", custInfo, jsonObject);
//
//                    repaymentOrderService.updateRepaymentOrder(repaymentOrder);
//
//                    //执行延迟代扣逻辑
//                    ibRepaymentService.deferredWithholdingSuccess(repaymentOrder);
//                    long end = System.currentTimeMillis();
//                    log.info("锁占用时间，耗时：" + (end - start) + " ms");
//                }finally {
//                    //释放锁
//                    redisCache.unLock(lockKey,lockValue);
//                }
//            } else {
//                log.info("deferredWithholding客户号{}第{}次获取账户锁失败", repaymentOrder.getCustNo(), j);
//
//                try {
//                    Thread.sleep(LoanConstants.CUST_ACCOUNT_LOCK_SLEEP_TIME);
//                } catch (InterruptedException e) {
//                    log.error("deferredWithholding线程sleep异常", e);
//                }
//            }
//        }
//        if(j>=LoanConstants.CUST_ACCOUNT_LOCK_REGET_COUNT){
//            ibRepaymentService.saveRepaymentException(repaymentOrder.getRepaymentNo(),BizConstants.REPAYMENT_EXCEPTION_TYPE_PAYSTACK,repaymentOrder.getRepaymentAmt(),repaymentOrder.getCustNo());
//        }
//
//    }

    /**
     * 优化代码
     *
     * @param serialNo
     * @param jsonObject
     */
    @Override
    @Transactional
    public void repaymentWebHook(String serialNo, JSONObject jsonObject) {
        RepaymentOrder repaymentOrder = repaymentOrderService.getDetailByPayTransSerialNoStatusSucc(serialNo);
        if (null == repaymentOrder) {
            log.info("未找到对应的repaymentOrder，serialNo：{}", serialNo);
            return;
        }
        CustomerInfo custInfo = getCustInfo(repaymentOrder.getCustNo());
        dealOrder(jsonObject, custInfo, repaymentOrder);
        doRepaymentLastService.lastInitRuleInAndAutoMat(repaymentOrder);
    }

    @Override
    @Transactional
    public void repaymentForCardWithhold(String serialNo, JSONObject jsonObject) {
        RepaymentOrder repaymentOrder = repaymentOrderService.getDetailByPayTransSerialNoStatusSucc(serialNo);
        if (null == repaymentOrder) {
            log.info("未找到对应的repaymentOrder，serialNo：{}", serialNo);
            return;
        }
        CustomerInfo custInfo = getCustInfo(repaymentOrder.getCustNo());
        dealOrder(jsonObject, custInfo, repaymentOrder);
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(repaymentOrder.getLoanSerialNo());
        iRepaymentSmsService.batchCardWithhold(loanIou,serialNo,repaymentOrder);
        doRepaymentLastService.lastInitRuleInAndAutoMat(repaymentOrder);
    }

    @Override
    @Transactional
    public void repaymentWebHookForVa(String serialNo, ExtTransferResult transferResult) {
        log.info("Paystack VA 还款：{},{}", serialNo, transferResult.toString());

        transferResult.setStatus(1);
        transferResultService.updateById(transferResult);

        BigDecimal amt = new BigDecimal(transferResult.getAmount()).divide(new BigDecimal(100));
        String repayToWalletSwitch = sysDictDataService.selectDictLabel("biz_switch", "repay_to_wallet_switch");
        if (StringUtils.equals(BizConstants.BIZ_SWITCH_OPEN, repayToWalletSwitch)) {
            log.info("Paystack VA 还款金额直接充值钱包开关开启，不进入还款，custNo = {}，reference = {}"
                    , transferResult.getCustNo(), serialNo);
            TransferVo transferVo = null;
            transferVo = TransferVo.builder().custNo(transferResult.getCustNo())
                    .transferAmt(amt)
                    .payTime(getPayTime(transferResult.getPaidAt()))
                    .actionType(BizConstants.OVERFLOW_TYPE_PAYSTACK_CHARGE)
                    .reference(serialNo).build();
            repayToWalletService.addOverflowAndPushWallet(transferVo);
            return;
        }
        //根据借据去冲账  判断借据是否是已完成状态
        LoanIou loanIou = loanIouService.getLatestOne(transferResult.getCustNo());

        // 需要创建repayMentOrder 状态是成功的
        RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderForWebhook(
                loanIou,
                BizConstants.LOAN_REPAYMENT_ORDER_TYPE_PAYSTACK_VA_WEBHOOK,
                serialNo,
                amt,
                getPayTime(transferResult.getPaidAt()),
                BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);

        if (null != loanIou && LoanIou.LOAN_IOU_STATUS_SETTLE != loanIou.getIouStatus()) {
            iRepaymentService.repaymentNoLock(loanIou, repaymentOrder.getRepaymentNo(), repaymentOrder.getActionType(), repaymentOrder.getRepaymentAmt(), BigDecimal.ZERO, 1);
            doRepaymentLastService.lastInitRuleInAndAutoMat(repaymentOrder);
        } else {
            log.info(repaymentOrder.getRepaymentNo() + "iou 结清了，进入溢缴款");
            // 进入溢缴款
            bLoanInfoService.doOverFlowAndWallet(repaymentOrder.getRepaymentAmt(), repaymentOrder);
        }
    }

    /**
     * 处理订单
     *
     * @param jsonObject
     * @param custInfo
     * @param repaymentOrder
     */
    private void dealOrder(JSONObject jsonObject, CustomerInfo custInfo, RepaymentOrder repaymentOrder) {
        String lockKey = LoanConstants.CUST_ACCOUNT_LOCK_KEY_PREFIX + repaymentOrder.getCustNo();
        RLock lock = redisCache.lock(lockKey);
        try {
            long start = System.currentTimeMillis();
            if (BizConstants.REPAYMENT_ORDER_STATUS_DOING == repaymentOrder.getRepayStatus()) {
                dealPross(jsonObject, custInfo, repaymentOrder);
            }
            long end = System.currentTimeMillis();
            log.info("锁占用时间，耗时：" + (end - start) + " ms");
        } catch (Exception e) {
            ibRepaymentService.saveRepaymentException(repaymentOrder.getRepaymentNo(), BizConstants.REPAYMENT_EXCEPTION_TYPE_PAYSTACK, repaymentOrder.getRepaymentAmt(), repaymentOrder.getCustNo());
            log.error("deferredWithholding", e);
            String className = this.getClass().getName();
            String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
            FeishuUtils.sendFeishuToMonit(className + "." + methodName, "deferredWithholding", repaymentOrder.getCustNo(), "", e);
        } finally {
            lock.unlock();
        }
    }

    private void dealPross(JSONObject jsonObject, CustomerInfo custInfo, RepaymentOrder repaymentOrder) {
        custInfo.setCustNo(repaymentOrder.getCustNo());
        custInfo.setUserId(getCustInfo(repaymentOrder.getCustNo()).getUserId());

        repaymentOrder.setPayTime(getPayTime(jsonObject));
        repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_SUCCESS);
        // externalApiService.dealTransferData(eventType, "webhook", custInfo, jsonObject);
        repaymentOrderService.updateRepaymentOrder(repaymentOrder);
        //执行延迟代扣逻辑
        ibRepaymentService.qucikRepayWithhol(repaymentOrder);
    }

    private static Date getPayTime(String paidAt) {
        try {
            return DateUtils.parseUTCText(paidAt);
        } catch (ParseException e) {
            log.warn("paidAt format error：{}", e.getMessage());
            return null;
        }
    }

    private static Date getPayTime(JSONObject debitResult) {
        try {
            String payTimeStr = StringUtils.getValue(debitResult, "paid_at");
            if (StringUtils.isBlank(payTimeStr)) {
                payTimeStr = StringUtils.getValue(debitResult, "transaction_date");
            }
            return DateUtils.parseUTCText(payTimeStr);
        } catch (Exception e) {
            log.warn("paidAt format error：{}", e.getMessage());
            return new Date();
        }
    }

}
